#include "evm_module.h"
#include <stddef.h>

static c_struct_signature my_struct_descr[] = {
  {"data", offsetof(msg_buffer_t, data), 'B', NULL},
  {"len", offsetof(msg_buffer_t, len), 'i', NULL},
  {NULL, 0, 0, NULL},
};

extern evm_val_t evm_struct_2_list(evm_t *e, evm_val_t *p, int argc, evm_val_t *v);
evm_val_t uart_msg_hander(evm_t * e,void *msg) {
    msg_buffer_t *msgbuff = (msg_buffer_t *)msg;

    evm_val_t args[2];
    args[0] = evm_mk_invoke(msg);
    my_struct_descr[0].arg = msgbuff->len;
    args[1] = evm_mk_invoke(my_struct_descr);

    return evm_struct_2_list(e, &(e->root), 2, args);
}

void uart_msg_free(void *msg) {
    if(msg == NULL)
        return;
    msg_buffer_t *msgbuff = (msg_buffer_t *)msg;

    evm_free(msgbuff->data);
    evm_free(msgbuff);
	msg = NULL;
}

static evm_val_t evm_module_uart_on(evm_t *e, evm_val_t *p, int argc, evm_val_t *v)
{
    if(argc!=3)
        return EVM_VAL_UNDEFINED;

    if(!evm_is_number(v) || !evm_is_number(v+1) || !evm_2_string(v+2))
        return EVM_VAL_UNDEFINED;

    int id = evm_2_integer(v);
    int instance = evm_2_integer(v+1);
    char *event = (char *)evm_2_string(v+2);
	
    evm_event_msg_t *msg = evm_module_msg_create();

    int str_len = strlen(event);
	msg->event = evm_malloc(str_len + 1);
	memcpy(msg->event, event,str_len);
	msg->event[str_len] = 0;

    msg->id = instance;

    msg->cb = uart_msg_hander;
    msg->free = uart_msg_free;

    evm_uart_t *uart = evm_module_uart_getInstance();
    if(uart ==NULL)
        return EVM_VAL_UNDEFINED;
    uart->on(id, msg);
    return EVM_VAL_UNDEFINED;
}

evm_err_t evm_module_uart(evm_t *e) {
    if(evm_module_uart_init() != 0)
        return ec_memory;

    evm_uart_t *uart = evm_module_uart_getInstance();
    if(uart ==NULL)
        return ec_err;

    evm_cffi_t funcs[] = {
        {"open", (uintptr_t)uart->open, "iiiiiii"},
        {"write", (uintptr_t)uart->write, "iipi"},
        {"read", (uintptr_t)uart->read, "iipii"},
        {"close", (uintptr_t)uart->close, "ii"},
        {NULL, 0, NULL}
    };

    evm_builtin_t builtin[] = {
        {"on", evm_mk_native((intptr_t)evm_module_uart_on)},
        {NULL, EVM_VAL_UNDEFINED}
    };
    evm_module_effi_create(e, "@native.uart", funcs , builtin);
    return e->err;
}
